#include <iostream>
using std::cout;
using std::endl;

class Data{
public:
    Data()
    { cout << "Data()" << endl; }

    int getData() const{
        return _data;
    }

    ~Data(){
        cout << "~Data()" << endl;
    }
private:
    int _data = 10;
};

class MiddleLayer{
public:
    MiddleLayer(Data * p)
    : _pdata(p)   
    { cout << "MiddleLayer(Data*)" << endl; }

    Data * operator->(){
        return _pdata;
    }

    Data & operator*(){
        return *_pdata;
    }

    ~MiddleLayer(){
        if(_pdata){
            delete _pdata;
            _pdata = nullptr;
        }
        cout << "~MiddleLayer()" << endl;
    }
    /* friend class ThirdLayer; */
private:
    Data * _pdata;
};

class ThirdLayer
{
public:
    ThirdLayer(MiddleLayer * pml)
    : _ml(pml)
    { cout << "ThirdLayer(MiddleLayer*)" << endl; }

    ~ThirdLayer(){
        if(_ml){
            delete _ml;
            _ml = nullptr;
        }
        cout << "~ThirdLayer()" << endl;
    }

    /* Data * operator->(){ */
    /*     return (*_ml)._pdata; */
    /* } */

    MiddleLayer & operator->(){
        return *_ml;
    }

    //两步解引用的方案二
    /* MiddleLayer & operator*(){ */
    /*     return *_ml; */
    /* } */

    //两步解引用的方案一
    /* Data * operator*(){ */
    /*     return (*_ml)._pdata; */
    /* } */

    //一步解引用的方案
    Data & operator*(){
        /* return *((*_ml)._pdata); */
        return *(*_ml);
    }
private:
    MiddleLayer * _ml;
};
void test1(){
    ThirdLayer tl(new MiddleLayer(new Data()));
    cout << tl->getData() << endl;
    //第一次调用ThirdLayer的箭头运算符重载函数
    //返回的是一个MiddleLayer对象
    cout << (tl.operator->())->getData() << endl;
    //因为之前已经在MiddleLayer中重载了箭头运算符
    //所以MiddleLayer对象可以调用本类的->运算符重载函数
    //返回的是一个Data*，就可以直接使用箭头运算符了
    ((tl.operator->()).operator->())->getData();

    cout << endl;
    //希望经过两步解引用访问getData
    //方案一：内层的*tl返回一个Data*
    //方案二：内存够的*tl返回一个MiddleLayer对象
    //(MiddleLayer已经进行过重载)
    //cout << (*(*tl)).getData() << endl;

    //*tl的返回值必须是Data对象才可以
    cout << (*tl).getData() << endl;
}


void test0(){
    Data * p1 = new Data();
    p1->getData();
    (*p1).getData();
    delete p1;
    p1 = nullptr;
    
    MiddleLayer ml(new Data());
    cout << ml->getData() << endl;
    cout << (ml.operator->())->getData() << endl;

    cout << (*ml).getData() << endl;
    cout << (ml.operator*()).getData() << endl;
}

int main(void){
    test1();
    return 0;
}
